package internal

import (
	"fmt"
	"sync"

	"github.com/globalsign/mgo/bson"
	log "github.com/sirupsen/logrus"

	"GameServer/Common/data"
	"GameServer/Common/utils"
	"GameServer/Game/dbmodule"
	"GameServer/Game/errors"
	"GameServer/Game/m"
	"GameServer/Game/rank"
	"GameServer/Game/sp"
)

type UnionManager struct {
	Unions []*m.Union // 公会列表
	rw     sync.RWMutex
}

func NewUnionManager() *UnionManager {
	return &UnionManager{
		Unions: make([]*m.Union, 0),
	}
}

func (this *UnionManager) Init() {
	err := dbmodule.MgoDB.GameDB.FindAll("union", nil, nil, &this.Unions)
	if err != nil {
		return
	}
	for _, item := range this.Unions {
		m.Cache.Put("union", item.Id.Hex(), item)
	}
}

func (this *UnionManager) Run(closeSig chan bool) {

}

func (this *UnionManager) Destroy() {

}

func (this *UnionManager) GetUnion(id string) (union *m.Union, err error) {
	v, isLoad, ok := m.Cache.GetForLoad("union", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会,id:%s", id))
		return
	}

	union = v.(*m.Union)
	if isLoad {
		for i, item := range this.Unions {
			if item.Id.Hex() == id {
				this.Unions[i] = union
				break
			}
		}
	}
	return
}

func (this *UnionManager) CheckName(name string) (ok bool) {
	for _, item := range this.Unions {
		if item.Name == name {
			return true
		}
	}
	return false
}

func (this *UnionManager) CheckShortName(name string) (ok bool) {
	for _, item := range this.Unions {
		if item.Name == name {
			return true
		}
	}
	return false
}

func (this *UnionManager) CreateUnion(u *m.User, req *sp.CreateUnionRequest) (union *m.Union, members map[string]*m.UnionMember, err error) {
	if this.CheckName(req.Name) {
		err = errors.NewErrcode(data.Errcode.UnionExist, "已经存在该公会名称")
		return
	}
	if this.CheckShortName(req.ShortName) {
		err = errors.NewErrcode(data.Errcode.UnionShortNameExist, "已经存在该公会短名称")
		return
	}

	union = &m.Union{
		Id: bson.NewObjectId(),
		Ico: &m.UnionIco{
			Bottom: req.Ico.Bottom,
			Pic:    req.Ico.Pic,
		},
		Name:       req.Name,
		ShortName:  req.ShortName,
		Desc:       req.Desc,
		JoinStatus: 1,
		Num:        0,
		Star:       u.StarVal(),
		CreateTime: utils.TNow().Unix(),
	}

	m.Cache.Put("union", union.Id.Hex(), union)

	union.Update(union)

	mMembers := m.NewUnionMembers().(*m.UnionMembers)
	mMembers.UnionId = union.Id
	member := &m.UnionMember{
		Uid:         u.Uid.Hex(),
		Name:        u.Name,
		Head:        u.Head,
		Score:       u.UnionScore,
		JoinTime:    utils.TNow().Unix(),
		Manager:     1,
		Star:        u.StarVal(),
		AvatarFrame: u.AvatarFrame,
	}
	u.UnionJionTime = member.JoinTime
	u.UnionCurTime = 0
	member.OnLine()
	mMembers.AddMember(union, member)
	m.Cache.Put("unionMembers", union.Id.Hex(), mMembers)

	mMembers.Update(mMembers)

	this.Unions = append(this.Unions, union)
	members = mMembers.Members
	u.UnionId = union.Id.Hex()
	return
}

func (this *UnionManager) UnionList(page, pageNum int) (r []*m.Union, num int) {
	start := page * pageNum
	rs := make([]*m.Union, 0)
	for _, item := range this.Unions {
		if item.JoinStatus == 2 {
			continue
		}
		//item.Num
		rs = append(rs, item)
	}
	num = len(rs)
	if start >= num {
		return
	}
	end := start + pageNum
	if end >= num {
		r = rs[start:]
		return
	}
	r = rs[start:end]
	return
}

func (this *UnionManager) UnionListAll(page, pageNum int, uid, name string) (list []*m.Union, num int) {
	num = len(this.Unions)

	list = make([]*m.Union, 0)
	//按公会UID查询
	if uid != "" {
		for _, val := range this.Unions {
			if val.Id.Hex() == uid {
				list = append(list, val)
				return
			}
		}
		return
	}
	//按公会昵称查询
	if name != "" {
		for _, val := range this.Unions {
			if val.Name == name {
				list = append(list, val)
			}
		}
		return
	}

	start := page * pageNum
	if start >= num {
		return
	}
	end := start + pageNum
	if end >= num {
		list = this.Unions[start:]
		return
	}
	list = this.Unions[start:end]
	return
}

func (this *UnionManager) UnionInfo(id string) (union *m.Union, members map[string]*m.UnionMember, err error) {

	union, err = this.GetUnion(id)
	if err != nil {
		return
	}

	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会成员,id:%s", id))
		return
	}
	members = v1.(*m.UnionMembers).MemberList()
	return
}

// 通过工会ID，获取公会成员
func (this *UnionManager) UnionMemberList(id string, page, pageNum int) (list []*m.UnionMember, num int) {
	list = make([]*m.UnionMember, 0)
	num = 0

	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	members := v1.(*m.UnionMembers).MemberList()
	for _, v := range members {
		list = append(list, v)
	}
	//计算起始位置
	start := page * pageNum
	//总成员数
	num = len(list)
	if start >= num {
		return
	}
	//计算结束位置
	end := start + pageNum
	if end >= num {
		list = list[start:]
		return
	}
	list = list[start:end]
	return
}

// 通过工会ID，获取工会成员uid
func (this *UnionManager) UnionMemberUidList(id string) (list []string) {
	list = make([]string, 0)
	if id == "" {
		return
	}
	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	members := v1.(*m.UnionMembers).MemberList()
	for _, v := range members {
		list = append(list, v.Uid)
	}
	return
}

func (this *UnionManager) UnionAddMerber(u *m.User, id string, broadcastFunc func(uid string, data interface{})) (union *m.Union, members map[string]*m.UnionMember, err error) {
	union, err = this.GetUnion(id)
	if err != nil {
		return
	}
	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", id))
		return
	}
	mMembers := v1.(*m.UnionMembers)

	if union.JoinStatus != 1 {
		err = errors.NewErrcode(data.Errcode.UnionNoPermission, fmt.Sprintf("公会不可加入,id:%s", id))
		return
	}

	if union.Num >= data.UnionConstEnum.LimitNum {
		err = errors.NewErrcode(data.Errcode.UnionFull, fmt.Sprintf("公会已经满员,id:%s", id))
		return
	}

	member := &m.UnionMember{
		Uid:         u.Uid.Hex(),
		Name:        u.Name,
		Head:        u.Head,
		Score:       u.UnionScore,
		JoinTime:    utils.TNow().Unix(),
		Manager:     0,
		Star:        u.StarVal(),
		AvatarFrame: u.AvatarFrame,
	}
	u.UnionJionTime = member.JoinTime
	u.UnionCurTime = 0
	member.OnLine()
	err = mMembers.AddMember(union, member)
	if err != nil {
		return
	}
	members = mMembers.MemberList()

	u.UnionId = union.Id.Hex()
	//更新星星数量
	union.UpdateStar()
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.IncreaseMember, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			if item.Uid == u.Uid.Hex() {
				continue
			}
			broadcastFunc(item.Uid, bData)
		}
	})

	return
}

func (this *UnionManager) UnionSearch(name string) (unionList []*m.Union, err error) {
	if name == "" {
		return nil, errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会,name：%s", name))
	}
	for _, item := range this.Unions {
		if item.Name == name {
			unionList = append(unionList, item)
			if len(unionList) == 2 {
				return unionList, nil
			}
		}
		if item.ShortName == name {
			unionList = append(unionList, item)
			if len(unionList) == 2 {
				return unionList, nil
			}
		}
	}
	if len(unionList) == 0 {
		return nil, errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会,name：%s", name))
	}
	return
}

func (this *UnionManager) UnionQuit(id string, u *m.User, broadcastFunc func(uid string, data interface{})) (err error) {
	return this.deleteUser(data.UnionEnum.PlayerExits, id, u, broadcastFunc)
}

func (this *UnionManager) UnionBan(id, meUid string, u *m.User, broadcastFunc func(uid string, data interface{})) (err error) {
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", id))
		return
	}
	mMembers := v.(*m.UnionMembers)

	me, ok := mMembers.GetMember(meUid)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id%s, 没有该成员,uid:%s", id, meUid))
		return
	}
	if me.Manager != 1 {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会,id:%s", id))
		return
	}
	if err = this.deleteUser(data.UnionEnum.Kick, id, u, broadcastFunc); err != nil {
		return
	}
	u.GetUnionBan().AddUnionBan(id)
	return
}

func (this *UnionManager) deleteUser(typ int64, id string, u *m.User, broadcastFunc func(uid string, data interface{})) (err error) {
	union, err := this.GetUnion(id)
	if err != nil {
		return
	}
	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", id))
		return
	}
	mMembers := v1.(*m.UnionMembers)
	uid := u.Uid.Hex()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id:%s, 没有该成员,uid:%s", id, uid))
		return
	}

	uEnergy := u.GetUnionEnergy()
	if uEnergy.ReqMsg != nil {
		// 删除该玩家在公会的体力请求
		m.DeleteUnionChatMsg(union.Id, u.Uid.Hex(), uEnergy.ReqMsg.Mid)
	}

	memberList := mMembers.MemberList()
	err = mMembers.DelMember(union, uid)
	if err != nil {
		return
	}

	u.UnionId = ""
	u.Update(u)
	// 工会人数为0，删除工会
	if union.Num == 0 {
		this.DeleteUnion(id)
		return
	}

	bData0 := this.getUnionMemberUpdateRequestData(typ, member)
	utils.AsyncFunc(func() {
		// 这里被踢的人收到一次，会额外收到一次，取消。
		// broadcastFunc(u.Uid.Hex(), bData0)
		for _, item := range memberList {
			broadcastFunc(item.Uid, bData0)
		}
	})
	//更新星星数量
	union.UpdateStar()
	langId := data.LangID.UnionQuit
	if typ == 3 {
		langId = data.LangID.UnionBan
	}
	this.UnionSysNotice(id, langId, []string{u.Name}, broadcastFunc)

	bDataUnionInfo := this.getUnionInfoUpdateRequest(union)

	utils.AsyncFunc(func() {
		for _, item := range memberList {
			broadcastFunc(item.Uid, bDataUnionInfo)
		}
	})

	if member.Manager == 1 {
		topM, err := mMembers.GetTopMember()
		if err != nil {
			return err
		}
		topM.Manager = 1
		// 更新公会成员数据
		mMembers.Update(mMembers)
		bData1 := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, topM)
		utils.AsyncFunc(func() {
			for _, item := range memberList {
				broadcastFunc(item.Uid, bData1)
			}
		})

		this.UnionSysNotice(id, data.LangID.UnionLeader, []string{topM.Name}, broadcastFunc)
	}
	return
}

func (this *UnionManager) deleteRobot(typ int64, id string, member *m.UnionMember, broadcastFunc func(uid string, data interface{})) (err error) {
	union, err := this.GetUnion(id)
	if err != nil {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会获取失败,id:%s", id))
		return
	}

	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", id))
		return
	}
	mMembers := v1.(*m.UnionMembers)
	// member, ok := mMembers.GetMember(um.Uid)
	// if !ok {
	// 	err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id:%s, 没有该成员,uid:%s", id, um.Uid))
	// 	return
	// }
	memberList := mMembers.MemberList()
	err = mMembers.DelMember(union, member.Uid)
	if err != nil {
		return
	}
	// 工会人数为0，删除工会
	if union.Num == 0 {
		this.DeleteUnion(id)
		return
	}

	bData0 := this.getUnionMemberUpdateRequestData(typ, member)
	utils.AsyncFunc(func() {
		// 这里被踢的人收到一次，会额外收到一次，取消。
		// broadcastFunc(u.Uid.Hex(), bData0)
		for _, item := range memberList {
			broadcastFunc(item.Uid, bData0)
		}
	})
	//更新星星数量
	union.UpdateStar()
	langId := data.LangID.UnionQuit
	if typ == 3 {
		langId = data.LangID.UnionBan
	}
	this.UnionSysNotice(id, langId, []string{member.Name}, broadcastFunc)

	bDataUnionInfo := this.getUnionInfoUpdateRequest(union)

	utils.AsyncFunc(func() {
		for _, item := range memberList {
			broadcastFunc(item.Uid, bDataUnionInfo)
		}
	})

	if member.Manager == 1 {
		topM, err := mMembers.GetTopMember()
		if err != nil {
			return err
		}
		topM.Manager = 1
		// 更新公会成员数据
		mMembers.Update(mMembers)
		bData1 := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, topM)
		utils.AsyncFunc(func() {
			for _, item := range memberList {
				broadcastFunc(item.Uid, bData1)
			}
		})

		this.UnionSysNotice(id, data.LangID.UnionLeader, []string{topM.Name}, broadcastFunc)
	}
	return
}

func (this *UnionManager) DeleteUnion(id string) {
	union, err := this.GetUnion(id)
	if err != nil {
		return
	}
	err = union.Delete()
	if err != nil {
		log.WithFields(log.Fields{
			"method": "DeleteUnion",
			"data":   id,
		}).Debug(err)
	}
	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会成员,id:%s", id))
		return
	}
	mMembers := v1.(*m.UnionMembers)

	err = mMembers.Delete()
	if err != nil {
		log.WithFields(log.Fields{
			"method": "DeleteUnionMembers",
			"data":   id,
		}).Debug(err)
	}

	newList := make([]*m.Union, 0)
	this.rw.Lock()
	for _, item := range this.Unions {
		if item.Id.Hex() == id {
			continue
		}
		newList = append(newList, item)
	}
	this.rw.Unlock()
	this.Unions = newList
}

func (this *UnionManager) OnLine(id, uid string, broadcastFunc func(uid string, data interface{})) {
	if id == "" || uid == "" {
		return
	}
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)
	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		return
	}

	member.OnLine()
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})

}

func (this *UnionManager) OffLine(id, uid string, broadcastFunc func(uid string, data interface{})) {
	if id == "" || uid == "" {
		return
	}
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)
	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		return
	}
	member.OffLine()
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})
}

// 清理公会成员
func (this *UnionManager) CleanUser(getUser func(uid string) (*m.User, bool), broadcastFunc func(uid string, data interface{})) {
	day10 := int64(10) * 24 * 60 * 60 //10天时间
	day5 := int64(5) * 24 * 60 * 60   //5天时间
	nowUnix := utils.TNow().Unix()    //当前时间
	// 公会普通玩家，5天没有登录，就踢出公会
	for _, union := range this.Unions {
		v, ok := m.Cache.Get("unionMembers", union.Id.Hex())
		if !ok {
			continue
		}
		mMembers := v.(*m.UnionMembers)
		members := mMembers.MemberList()
		for _, member := range members {
			if member.OffLineTime > 0 && member.Manager == 0 && member.OffLineTime+day5 < nowUnix {
				user, ok := getUser(member.Uid)
				if !ok {
					continue
				}
				this.deleteUser(data.UnionEnum.Kick, union.Id.Hex(), user, broadcastFunc)
			}
		}
	}

	// 会长10天没有上线 直接把它干掉
	for _, union := range this.Unions {
		v, ok := m.Cache.Get("unionMembers", union.Id.Hex())
		if !ok {
			continue
		}
		mMembers := v.(*m.UnionMembers)
		members := mMembers.MemberList()
		for _, member := range members {
			if member.OffLineTime > 0 && member.Manager == 1 && member.OffLineTime+day10 < nowUnix {
				if user, ok := getUser(member.Uid); ok {
					this.deleteUser(data.UnionEnum.PlayerExits, union.Id.Hex(), user, broadcastFunc)
				} else {
					this.deleteRobot(data.UnionEnum.PlayerExits, union.Id.Hex(), member, broadcastFunc)
				}
				break
			}
		}
	}
}

func (this *UnionManager) UpdateUserAvatarFrame(id string, uid string, frameId int64, broadcastFunc func(uid string, data interface{})) {
	if id == "" || uid == "" {
		return
	}
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)

	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		return
	}
	member.AvatarFrame = frameId

	mMembers.Update(mMembers)
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})
}

func (this *UnionManager) UpdateUserNameAndHead(u *m.User, broadcastFunc func(uid string, data interface{})) {
	if u.UnionId == "" {
		return
	}
	v, ok := m.Cache.Get("unionMembers", u.UnionId)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)

	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(u.Uid.Hex())
	if !ok {
		return
	}
	member.Name = u.Name
	member.Head = u.Head

	mMembers.Update(mMembers)
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})
}

func (this *UnionManager) UpdateUserStar(id string, uid string, star int64, broadcastFunc func(uid string, data interface{})) {
	if id == "" || uid == "" {
		return
	}
	union, err := this.GetUnion(id)
	if err != nil {
		return
	}
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)

	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		return
	}
	member.Star = star
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})
	union.UpdateStar()

	bDataUnionInfo := this.getUnionInfoUpdateRequest(union)

	rank.AddUnionRank(union)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bDataUnionInfo)
		}
	})
}

// 玩家积分更新
func (this *UnionManager) UpdateUserScore(id string, uid string, score int64, broadcastFunc func(uid string, data interface{})) {
	if id == "" || uid == "" {
		return
	}

	union, err := this.GetUnion(id)
	if err != nil {
		return
	}
	v, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		return
	}
	mMembers := v.(*m.UnionMembers)

	members := mMembers.MemberList()
	member, ok := mMembers.GetMember(uid)
	if !ok {
		return
	}
	defer mMembers.Update(mMembers)
	member.Score = score
	bData := this.getUnionMemberUpdateRequestData(data.UnionEnum.PlayerUpdate, member)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData)
		}
	})

	bDataUnionInfo := this.getUnionInfoUpdateRequest(union)

	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bDataUnionInfo)
		}
	})
}

func (this *UnionManager) getUnionMemberUpdateRequestData(typ int64, member *m.UnionMember) *sp.UnionMemberUpdateRequest {
	return &sp.UnionMemberUpdateRequest{
		Typ: typ,
		Member: &sp.UnionMember{
			Uid:         member.Uid,
			Name:        member.Name,
			Head:        member.Head,
			Score:       member.Score,
			JoinTime:    member.JoinTime,
			Manager:     member.Manager,
			OnLine:      member.OnLineVal(),
			Star:        member.Star,
			AvatarFrame: member.AvatarFrame,
		},
	}
}

func (this *UnionManager) getUnionInfoUpdateRequest(union *m.Union) (r *sp.UnionInfoUpdateRequest) {
	r = &sp.UnionInfoUpdateRequest{
		Info: &sp.UnionInfo{
			Id:   union.Id.Hex(),
			Name: union.Name,
			Ico: &sp.UnionIco{
				Bottom: union.Ico.Bottom,
				Pic:    union.Ico.Pic,
			},
			Score:      union.Score,
			Desc:       union.Desc,
			JoinStatus: union.JoinStatus,
			Num:        union.Num,
			ShortName:  union.ShortName,
			Star:       union.Star,
		},
	}
	return
}

func (this *UnionManager) UpdateUnionInfo(id string, uid string, req *sp.UnionInfoEditRequest, broadcastFunc func(uid string, data interface{})) (err error) {
	if id == "" || uid == "" {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("没有此公会,id:%s, uid:%s", id, uid))
		return
	}

	union, err := this.GetUnion(id)
	if err != nil {
		return
	}
	v1, ok := m.Cache.Get("unionMembers", id)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", id))
		return
	}
	mMembers := v1.(*m.UnionMembers)

	member, ok := mMembers.GetMember(uid)
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id:%s, 没有该成员,uid:%s", id, uid))
		return
	}

	if member.Manager != 1 {
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("不是会长,id:%s, uid:%s", id, uid))
		return
	}
	if req.Name == "" && (req.Ico == nil || (req.Ico.Bottom == "" && req.Ico.Pic == "")) && req.ShortName == "" && req.Desc == "" && req.JoinStatus == 0 {
		err = errors.NewErrcode(data.Errcode.ServerErr, "更改公会信息错误参数为空")
		return
	}

	if req.Name != "" && req.Name != union.Name && this.CheckName(req.Name) {
		err = errors.NewErrcode(data.Errcode.UnionExist, "已经存在该公会名称")
		return
	}
	if req.ShortName != "" && req.ShortName != union.ShortName && this.CheckShortName(req.ShortName) {
		err = errors.NewErrcode(data.Errcode.UnionShortNameExist, "已经存在该公会短名称")
		return
	}

	defer union.Update(union)
	if req.Name != "" {
		union.Name = req.Name
	}
	if req.ShortName != "" {
		union.ShortName = req.ShortName
	}

	if req.Ico != nil {
		if req.Ico.Bottom != "" {
			union.Ico.Bottom = req.Ico.Bottom
		}
		if req.Ico.Pic != "" {
			union.Ico.Pic = req.Ico.Pic
		}
	}

	if req.Desc != "" {
		union.Desc = req.Desc
	}
	if req.JoinStatus != 0 {
		union.JoinStatus = req.JoinStatus
	}

	infoData := &sp.UnionInfoUpdateRequest{
		Info: &sp.UnionInfo{
			Id:   union.Id.Hex(),
			Name: union.Name,
			Ico: &sp.UnionIco{
				Bottom: union.Ico.Bottom,
				Pic:    union.Ico.Pic,
			},
			Score:      union.Score,
			Desc:       union.Desc,
			JoinStatus: union.JoinStatus,
			Num:        union.Num,
			ShortName:  union.ShortName,
			Star:       union.Star,
		},
	}

	members := mMembers.MemberList()

	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, infoData)
		}
	})
	return nil

}

// 会长禅让，然后跑路了。
func (this *UnionManager) PresidentAbdicated(unionId, leaderUid, heirUid string, broadcastFunc func(uid string, data interface{})) (err error) {
	if unionId == "" || leaderUid == "" || heirUid == "" {
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("工会id:%s,会长uid:%s,继承人uid:%s", unionId, leaderUid, heirUid))
		return
	}
	v1, ok := m.Cache.Get("unionMembers", unionId) // 获取工会成员
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnion, fmt.Sprintf("公会成员获取失败,id:%s", unionId))
		return
	}
	mMembers := v1.(*m.UnionMembers)

	leader, ok := mMembers.GetMember(leaderUid) // 获取会长信息
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id:%s, 没有该成员,uid:%s", unionId, leaderUid))
		return
	}

	if leader.Manager != 1 { // 该玩家不是会长
		err = errors.NewErrcode(data.Errcode.ServerErr, fmt.Sprintf("不是会长,公会id:%s, uid:%s", unionId, leaderUid))
		return
	}
	heir, ok := mMembers.GetMember(heirUid) // 获取继承会长的玩家
	if !ok {
		err = errors.NewErrcode(data.Errcode.NoUnionUser, fmt.Sprintf("公会id:%s, 没有该成员,uid:%s", unionId, heirUid))
		return
	}

	// 会长跑路，继承者成为会长。
	leader.Manager = 0
	heir.Manager = 1
	mMembers.Update(mMembers)

	members := mMembers.MemberList()

	bData1 := this.getUnionMemberUpdateRequestData(data.UnionEnum.PresidentAbdicated, leader)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData1)
		}
	})

	bData2 := this.getUnionMemberUpdateRequestData(data.UnionEnum.PresidentAbdicated, heir)
	utils.AsyncFunc(func() {
		for _, item := range members {
			broadcastFunc(item.Uid, bData2)
		}
	})
	return
}

// 推荐公会
func (this *UnionManager) RecomUnion() (union *m.Union, rankId int64) {
	this.rw.RLock()
	for idx, item := range this.Unions {
		if item.Num < 45 {
			union = item
			rankId = int64(idx) + 1
			break
		}
	}
	this.rw.RUnlock()
	if union != nil {
		return
	}

	// 没有符合要求的公会 创建一个新公会 会长是机器人
	roboot := NewUnionRobot()
	// 自动创建新公会
	union = NewUnion(roboot)

	this.rw.Lock()
	this.Unions = append(this.Unions, union)
	rankId = int64(len(this.Unions))
	this.rw.Unlock()

	return
}

// 创建公会会长机器人
func NewUnionRobot() (us *m.User) {
	lockBlockTid := utils.RandomInt64(1, 63)
	number := utils.RandomInt64(1, 1000)
	us = &m.User{
		Robot:         true,
		Uid:           bson.NewObjectId(),
		Number:        number,
		Name:          utils.GenName(),                                     //生成随机名字
		Head:          utils.GenDefaultHead(),                              //随机头像4选1
		Gold:          utils.RandomInt64(50000, 10000) * lockBlockTid * 10, // 机器人金币上调10倍
		Diamon:        utils.RandomInt64(1, 100000),
		Shield:        utils.RandomInt64(0, 3),
		LastLoginTime: utils.TNow().Unix(),
		Pos:           &m.PosInfo{LockBlockTid: lockBlockTid, LayerId: 1},
		MaxPos:        &m.PosInfo{LockBlockTid: lockBlockTid, LayerId: 1},
		AvatarFrame:   data.AvatarFrameEnum.DefaultFrame, // 默认头像框
	}
	return
}

// 创建一个新的公会
func NewUnion(us *m.User) (union *m.Union) {
	union = &m.Union{
		Id: bson.NewObjectId(),
		Ico: &m.UnionIco{
			Bottom: "Icon_230101",
			Pic:    "Icon_230201",
		},
		Name:       utils.GenUnionName(),
		ShortName:  utils.GenUnionShortName(),
		Desc:       "We all in one adventure.",
		JoinStatus: 1,
		Num:        0,
		Star:       us.StarVal(),
		CreateTime: utils.TNow().Unix(),
	}

	union.Update(union)

	mMembers := m.NewUnionMembers().(*m.UnionMembers)
	mMembers.UnionId = union.Id
	member := &m.UnionMember{
		Uid:         us.Uid.Hex(),
		Name:        us.Name,
		Head:        us.Head,
		Score:       us.UnionScore,
		JoinTime:    utils.TNow().Unix(),
		Manager:     1,
		Star:        0,
		AvatarFrame: us.AvatarFrame,
	}
	member.OnLine()
	mMembers.AddMember(union, member)

	mMembers.Update(mMembers)
	return
}
